spb/chat-spboucher Public
Private universal chat interface over the OpenRouter ecosystem — 400+ models, branching, streaming, usage tracking. Next.js 16 + SQLite, PWA, deployed on m4m64a at chat.spboucher.ai
TypeScript 78.8%
CSS 15.1%
JavaScript 4.9%
Shell 1.2%
1// Author: Simon-Pierre Boucher2// Contact: contact@spboucher.ai3// Project: chat.spboucher.ai45import { NextResponse, type NextRequest } from "next/server";6import { requireSession } from "@/lib/auth/guard";7import {8 deleteConversation,9 getConversation,10 listMessages,11 getMessage,12 updateConversation,13} from "@/lib/conversations";1415export const runtime = "nodejs";1617type Params = { params: Promise<{ id: string }> };1819export async function GET(_req: NextRequest, { params }: Params) {20 const { unauthorized } = await requireSession();21 if (unauthorized) return unauthorized;22 const { id } = await params;23 const conversation = getConversation(id);24 if (!conversation) return NextResponse.json({ error: "Conversation not found." }, { status: 404 });25 return NextResponse.json({ conversation, messages: listMessages(id) });26}2728export async function PATCH(req: NextRequest, { params }: Params) {29 const { unauthorized } = await requireSession();30 if (unauthorized) return unauthorized;31 const { id } = await params;32 if (!getConversation(id)) return NextResponse.json({ error: "Conversation not found." }, { status: 404 });33 let body: { title?: string; pinned?: boolean; currentLeafId?: string | null };34 try {35 body = await req.json();36 } catch {37 return NextResponse.json({ error: "Invalid request." }, { status: 400 });38 }39 if (body.currentLeafId) {40 const leaf = getMessage(body.currentLeafId);41 if (!leaf || leaf.conversation_id !== id) {42 return NextResponse.json({ error: "Invalid leaf message." }, { status: 400 });43 }44 }45 updateConversation(id, body);46 return NextResponse.json({ conversation: getConversation(id) });47}4849export async function DELETE(_req: NextRequest, { params }: Params) {50 const { unauthorized } = await requireSession();51 if (unauthorized) return unauthorized;52 const { id } = await params;53 deleteConversation(id);54 return NextResponse.json({ ok: true });55}56